﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Money
{
    // TODO in theory this could be expanded to include what we do for hiding and also display of an icon for the likes of edited? These are available in match fields
    // TODO should we add in an option for italic as well as bold
    public partial class GridFormatConfigurationForm : Form
    {
        private enum State
        {
            Add,
            Edit,
            View,
            Saved,
            Cancel
        }

        State _state = State.View;
        bool _formLoaded = false;
        bool _changed = false;

        private List<GridFormatTransactionMatch> _formats;
        private GridFormatTransactionMatch _formatMatch = null;
        private IDataSet _dataInterface = null;

        private int _lastSelectedRow = -1;

        public GridFormatConfigurationForm(List<GridFormatTransactionMatch> formats, IDataSet dataInterface)
        {
            InitializeComponent();

            _dataInterface = dataInterface;

            _category.DataSource = _dataInterface.Categories;
            _category.DisplayMember = "Name";
            _category.ValueMember = "Id";

            _categoryGroup.DataSource = _dataInterface.Categories.GetCategoryGroups().ToList();
            _categoryGroup.DisplayMember = "Name";
            _categoryGroup.ValueMember = "Id";

            _account.DataSource = _dataInterface.Accounts;
            _account.DisplayMember = "Name";
            _account.ValueMember = "Name";

            _type.DataSource = Enum.GetValues(typeof(Transaction.TransactionType));

            _formats = formats;

            _grid.AutoGenerateColumns = false;

            _grid.DataSource = formats;

            SetGridDataSource();

            _actionButton.Enabled = false;
        }

        private void PopulateEditingControls(GridFormatTransactionMatch formatMatch)
        {
            // populate the match controls

            if (formatMatch.MatchRule.MaximumAmount != null || formatMatch.MatchRule.MinimumAmount != null)
            {
                _enableAmount.Checked = true;
            }
            else
            {
                _enableAmount.Checked = false;
            }

            if (formatMatch.MatchRule.MaximumAmount != null)
            {
                _maxAmount.Text = formatMatch.MatchRule.MaximumAmount.ToString();
            }
            else
            {
                _maxAmount.Text = "";
            }

            if (formatMatch.MatchRule.MinimumAmount != null)
            {
                _minAmount.Text = formatMatch.MatchRule.MinimumAmount.ToString();
            }
            else
            {
                _minAmount.Text = "";
            }

            if (formatMatch.MatchRule.CategoryId != null)
            {
                _enableCategory.Checked = true;
                _category.SelectedValue = formatMatch.MatchRule.CategoryId;
            }
            else
            {
                _enableCategory.Checked = false;
                _category.SelectedIndex = -1;
            }

            if (formatMatch.MatchRule.CategoryGroupId != null)
            {
                _enableCategoryGroup.Checked = true;
                _categoryGroup.SelectedValue = formatMatch.MatchRule.CategoryGroupId;
            }
            else
            {
                _enableCategoryGroup.Checked = false;
                _categoryGroup.SelectedIndex = -1;
            }

            if (formatMatch.MatchRule.Type != null)
            {
                _enableType.Checked = true;
                _type.SelectedValue = formatMatch.MatchRule.Type;
            }
            else
            {
                _enableType.Checked = false;
                _type.SelectedIndex = -1;
            }

            if (formatMatch.MatchRule.Account != null)
            {
                _enableAccount.Checked = true;
                _account.SelectedValue = formatMatch.MatchRule.Account;
            }
            else
            {
                _enableAccount.Checked = false;
                _account.SelectedIndex = -1;
            }

            if (!String.IsNullOrWhiteSpace(formatMatch.MatchRule.Description))
            {
                _description.Text = formatMatch.MatchRule.Description;
                _enableDescription.Checked = true;
            }
            else
            {
                _description.Text = "";
                _enableDescription.Checked = false;
            }

            // populate the format controls
            if (formatMatch.Format.Bold != null)
            {
                _bold.Checked = (bool)formatMatch.Format.Bold;
            }
            else
            {
                _bold.Checked = false;
            }

            if (formatMatch.Format.Italic != null)
            {
                _italic.Checked = true;
            }
            else
            {
                _italic.Checked = false;
            }

            if (formatMatch.Format.Hide != null)
            {
                _hide.Checked = true;
            }
            else
            {
                _hide.Checked = false;
            }

            if (formatMatch.Format.Color != Color.Empty)
            {
                _background.BackColor = formatMatch.Format.Color;
                _enableBackground.Checked = true;
            }
            else
            {
                _background.BackColor = SystemColors.Window;
                _enableBackground.Checked = false;
            }

            if (formatMatch.Format.FontColor != Color.Empty)
            {
                _font.BackColor = formatMatch.Format.FontColor;
                _enableFont.Checked = true;
            }
            else
            {
                _font.BackColor = SystemColors.WindowText;
                _enableFont.Checked = false;
            }

            if (formatMatch.Format.SelectedColor != Color.Empty)
            {
                _selected.BackColor = formatMatch.Format.SelectedColor;
                _enableSelected.Checked = true;
            }
            else
            {
                _selected.BackColor = SystemColors.Highlight;
                _enableSelected.Checked = false;
            }

            _changed = false;
        }

        private void SetGridDataSource()
        {
            _grid.DataSource = null;
            _grid.DataSource = _formats;
        }

        private void _actionButton_Click(object sender, EventArgs e)
        {
            GridFormatTransactionMatch match = null;

            switch (_state)
            {
                case State.Edit:
                    match = _formatMatch;
                    break;

                case State.Add:
                    match = new GridFormatTransactionMatch();
                    _formats.Add(match);
                    break;
            }

            CreateFormatMatch(match);

            ClearControls();

            SetGridDataSource();

            _grid.Refresh();

            _state = State.View;

            _changed = false;
        }

        private void _clearButton_Click(object sender, EventArgs e)
        {
            ClearControls();
            EnableControls(true);
            _state = State.Add;
            ConfigureActionButton();
            _grid.ClearSelection();
        }

        private void ClearControls()
        {
            PopulateEditingControls(new GridFormatTransactionMatch());
        }


        private void _grid_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            DataGridView grid = sender as DataGridView;

            if (grid == null)
            {
                return;
            }

            if (e.RowIndex < 0)
            {
                return;
            }

            switch (e.Button)
            {
                case System.Windows.Forms.MouseButtons.Left:
                    break;

                case System.Windows.Forms.MouseButtons.Right:
                    if (grid.SelectedRows.Count > 1)
                    {
                        deleteEntriesMenuItem.Text = "Delete Entries";
                    }
                    else
                    {
                        deleteEntriesMenuItem.Text = "Delete Entry";
                    }
                    contextMenu.Show(System.Windows.Forms.Cursor.Position);
                    break;
            }
        }

        private void deleteEntriesMenuItem_Click(object sender, EventArgs e)
        {
            DataGridView grid = _grid;

            if (grid != null)
            {
                if (grid.SelectedRows.Count > 0)
                {
                    DialogResult result = MessageBox.Show("Do you want to delete " + grid.SelectedRows.Count + " entries?", "Confirm Delete", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2);

                    if (result == System.Windows.Forms.DialogResult.Yes)
                    {
                        foreach (DataGridViewRow row in grid.SelectedRows)
                        {
                            GridFormatTransactionMatch match = row.DataBoundItem as GridFormatTransactionMatch;

                            if (match != null)
                            {
                                _formats.Remove(match);
                            }
                        }

                        ClearControls();
                        SetGridDataSource();
                    }
                }
            }
        }

        private void _descriptionGrid_SelectionChanged(object sender, EventArgs e)
        {
            if (!_formLoaded)
            {
                return;
            }

            // if last row is equal to -2 then this is a special case where we do not want to do anything as we are mid-operation
            if (_lastSelectedRow == -2)
            {
                return;
            }

            // if we have no selection then we can add a record
            if (_grid.SelectedRows.Count == 0)
            {
                EnableControls(true);
                ClearControls();
                _state = State.Add;
                _lastSelectedRow = -1;
            }
            // if we have one selection then we can change an entry
            else if (_grid.SelectedRows.Count == 1)
            {
                if (_lastSelectedRow == _grid.SelectedRows[0].Index)
                {
                    return;
                }

                GridFormatTransactionMatch formatMatch = _grid.SelectedRows[0].DataBoundItem as GridFormatTransactionMatch;

                if (formatMatch != null)
                {
                    PopulateEditingControls(formatMatch);

                    EnableControls(true);
                    _formatMatch = formatMatch;
                    _state = State.Edit;
                    _lastSelectedRow = _grid.SelectedRows[0].Index;
                }
                else
                {
                    _lastSelectedRow = -1;
                    EnableControls(true);
                    ClearControls();
                    _state = State.Add;
                }

            }
            // if we have more than one then we cannot od anything other than delete so disable edit controls
            else
            {
                EnableControls(false);

                ClearControls();
                _state = State.View;
            }

            ConfigureActionButton();
        }

        /// <summary>
        /// This method is called when any data entry object is edited on the screen. Check if we should change control operation if we have a changed value
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ValidAfterEdit(object sender, EventArgs e)
        {
            ConfigureActionButton();
        }

        private void CreateFormatMatch(GridFormatTransactionMatch match)
        {
            if (_enableAmount.Checked)
            {
                try
                {
                    match.MatchRule.MaximumAmount = Convert.ToDecimal(_maxAmount.Text);
                }
                catch
                {
                    match.MatchRule.MaximumAmount = null;
                }

                try
                {
                    match.MatchRule.MinimumAmount = Convert.ToDecimal(_minAmount.Text);
                }
                catch
                {
                    match.MatchRule.MinimumAmount = null;
                }
            }
            else
            {
                match.MatchRule.MaximumAmount = null;
                match.MatchRule.MinimumAmount = null;
            }

            if (_enableCategory.Checked && _category.SelectedIndex != -1)
            {
                match.MatchRule.CategoryId = (int)_category.SelectedValue;
            }
            else
            {
                match.MatchRule.CategoryId = null;
            }

            if (_enableCategoryGroup.Checked && _categoryGroup.SelectedIndex != -1)
            {
                match.MatchRule.CategoryGroupId = (int)_categoryGroup.SelectedValue;
            }
            else
            {
                match.MatchRule.CategoryGroupId = null;
            }

            if (_enableType.Checked && _type.SelectedIndex != -1)
            {
                match.MatchRule.Type = (Transaction.TransactionType)_type.SelectedValue;
            }
            else
            {
                match.MatchRule.Type = null;
            }

            if (_enableAccount.Checked && _account.SelectedIndex != -1)
            {
                match.MatchRule.Account = _account.Text;
            }
            else
            {
                match.MatchRule.Account = null;
            }

            if (_enableDescription.Checked)
            {
                match.MatchRule.Description = _description.Text;
            }
            else
            {
                match.MatchRule.Description = null;
            }

            if (_enableFont.Checked)
            {
                match.Format.FontColor = _font.BackColor;
            }
            else
            {
                match.Format.FontColor = Color.Empty;
            }

            if (_enableBackground.Checked)
            {
                match.Format.Color = _background.BackColor;
            }
            else
            {
                match.Format.Color = Color.Empty;
            }

            if (_enableSelected.Checked)
            {
                match.Format.SelectedColor = _selected.BackColor;
            }
            else
            {
                match.Format.SelectedColor = Color.Empty;
            }

            if (_bold.Checked)
            {
                match.Format.Bold = true;
            }
            else
            {
                match.Format.Bold = false;
            }

            if (_italic.Checked)
            {
                match.Format.Italic = true;
            }
            else
            {
                match.Format.Italic = false;
            }

            if (_hide.Checked)
            {
                match.Format.Hide = true;
            }
            else
            {
                match.Format.Hide = false;
            }
        }

        private void ConfigureActionButton()
        {
            // TODO the validation for add and edit is basic at the minute and only checks that one of each area is enabled, it doesnt actually check that their is a valid value
            switch (_state)
            {
                case State.Add:
                    _actionButton.Text = _state.ToString();
                    if (_changed && ValidateEntry())
                    {
                        _actionButton.Enabled = true;
                    }
                    else
                    {
                        _actionButton.Enabled = false;
                    }
                    break;

                case State.Edit:
                    _actionButton.Text = _state.ToString();

                    if (_changed && ValidateEntry())
                    {
                        _actionButton.Enabled = true;
                    }
                    else
                    {
                        _actionButton.Enabled = false;
                    }
                    break;

                default:
                    _actionButton.Enabled = false;
                    break;
            }
        }

        private bool ValidateEntry()
        {
            bool validEntry = false;

            if (((_enableAmount.Checked && (!String.IsNullOrWhiteSpace(_maxAmount.Text) || !String.IsNullOrWhiteSpace(_minAmount.Text))) ||
                 (_enableDescription.Checked && (!String.IsNullOrWhiteSpace(_description.Text))) ||
                 (_enableCategory.Checked && _category.SelectedIndex != -1) ||
                 (_enableCategoryGroup.Checked && _categoryGroup.SelectedIndex != -1) ||
                 (_enableAccount.Checked && _account.SelectedIndex != -1) ||
                 (_enableType.Checked && _type.SelectedIndex != -1)) &&
                ((_enableBackground.Checked) ||
                 (_enableFont.Checked) ||
                 (_enableSelected.Checked) ||
                 (_bold.Checked) ||
                 (_italic.Checked) ||
                 (_hide.Checked)))
            {
                validEntry = true;
            }

            return validEntry;
        }

        private bool EditChanged(CategoriseShortcut shortcut)
        {
            bool changed = false;
            
            // TODO we need to add comment check in here but it is complicated by the fact that comment can be null
            // TODO check not complete at present, simplified
            if (_changed)
            {
                changed = true;
            }

            return changed;
        }

        private void EnableControls(bool state)
        {
        }

        private void _grid_DataError(object sender, DataGridViewDataErrorEventArgs e)
        {

        }

        private void CategoriseShortcutsForm_Load(object sender, EventArgs e)
        {
            _clearButton_Click(this, new EventArgs());
            ConfigureActionButton();
            _formLoaded = true;
        }

        private void _enable_click(object sender, EventArgs e)
        {
            ValidAfterEdit(sender, e);
        }

        private void _grid_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            DataGridView dataGrid = (DataGridView)sender;

            // TODO have a configurable set of rules that match a transaction and apply a set colour
            if (e.RowIndex >= 0)
            {
                GridFormatTransactionMatch format = dataGrid.Rows[e.RowIndex].DataBoundItem as GridFormatTransactionMatch;

                if (format != null)
                {
                    if (format.Format.Color != Color.Empty)
                    {
                        e.CellStyle.BackColor = format.Format.Color;
                    }
                    if (format.Format.SelectedColor != Color.Empty)
                    {
                        e.CellStyle.SelectionBackColor = format.Format.SelectedColor;
                    }
                    if (format.Format.FontColor != Color.Empty)
                    {
                        e.CellStyle.ForeColor = format.Format.FontColor;
                    }

                    FontStyle fontStyle = FontStyle.Regular;
                    
                    if (format.Format.Bold == true)
                    {
                        fontStyle = FontStyle.Bold;
                    }
                    if (format.Format.Italic == true)
                    {
                        fontStyle |= FontStyle.Italic;
                    }
                    e.CellStyle.Font = new Font(e.CellStyle.Font, fontStyle);

                }

                return;
            }
        }

        private void _enableAmount_CheckedChanged(object sender, EventArgs e)
        {
            _amountLabel.Enabled = _maxAmount.Enabled = _minAmount.Enabled = _enableAmount.Checked;
            _changed = true;
            ValidAfterEdit(sender, e);
        }

        private void _enableDescription_CheckedChanged(object sender, EventArgs e)
        {
            _descriptionLabel.Enabled = _description.Enabled = _enableDescription.Checked;
            _changed = true;
            ValidAfterEdit(sender, e);
        }

        private void _enableCategory_CheckedChanged(object sender, EventArgs e)
        {
            _categoryLabel.Enabled = _category.Enabled = _enableCategory.Checked;
            _changed = true;
            ValidAfterEdit(sender, e);
        }

        private void _enableCategoryGroup_CheckedChanged(object sender, EventArgs e)
        {
            _categoryGroupLabel.Enabled = _categoryGroup.Enabled = _enableCategoryGroup.Checked;
            _changed = true;
            ValidAfterEdit(sender, e);
        }

        private void _enableAccount_CheckedChanged(object sender, EventArgs e)
        {
            _accountLabel.Enabled = _account.Enabled = _enableAccount.Checked;
        }

        private void _colour_Click(object sender, EventArgs e)
        {
            PictureBox box = sender as PictureBox;

            if(box != null)
            {
                if (_colourPicker.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    box.BackColor = _colourPicker.Color;
                    _changed = true;
                    ValidAfterEdit(sender, e);
                }
            }
        }

        private void _data_changed(object sender, EventArgs e)
        {
            _changed = true;
            ValidAfterEdit(sender, e);
        }

        private void _enableType_CheckedChanged(object sender, EventArgs e)
        {
            _typeLabel.Enabled = _type.Enabled = _enableType.Checked;
        }
    }
}
